package com.hsylient.javase.chapter03;

import java.util.Arrays;

/**
 * 模拟jdk中的ArrayList
 */
public class MyArrayList<E> {

    /**
     * 初始化容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    private static Object[] EMPTY_ELEMENT_DATA = {};

    private static final Object[] DEFAULT_CAPACITY_EMPTY_ELEMENT_DATA = {};

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private Object[] elementDate;

    private int size;

    protected transient int modCount = 0;

    public MyArrayList() {
        this.elementDate = DEFAULT_CAPACITY_EMPTY_ELEMENT_DATA;
    }

    public MyArrayList(int initCapacity) {
        if (initCapacity < 0) {
            throw new IllegalArgumentException("初始化容量不能为负数");
        } else if (initCapacity == 0){
            this.elementDate = EMPTY_ELEMENT_DATA;
        } else {
            this.elementDate = new Object[initCapacity];
        }
    }

    public boolean add(E e) {
        modCount++;
        add(e, elementDate, size);
        return true;
    }
    
    private void add(E e, Object[] elementDate, int s) {
        if (s == elementDate.length)
            grow();
        elementDate[s] = e;
        size = s + 1;
    }

    private Object[] grow() {
        return grow(size + 1);
    }

    private Object[] grow(int minCapacity) {
        return elementDate = Arrays.copyOf(elementDate, newCapacity(minCapacity));
    }

    private int newCapacity(int minCapacity) {
        int oldCapacity = elementDate.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementDate == DEFAULT_CAPACITY_EMPTY_ELEMENT_DATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0)
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
                ? newCapacity
                : hugeCapacity(minCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
                ? Integer.MAX_VALUE
                : MAX_ARRAY_SIZE;
    }


    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }
}
